package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.cloudfun.campusshare.common.constant.*;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.WithdrawApplicationDTO;
import com.cloudfun.campusshare.common.model.dto.WithdrawHisDTO;
import com.cloudfun.campusshare.common.model.dto.kjt.KjtSubMerchantWithdrawalCashNotifyDTO;
import com.cloudfun.campusshare.common.model.dto.kjt.KjtSubMerchantWithdrawalCashReqDTO;
import com.cloudfun.campusshare.common.model.dto.kjt.KjtSubMerchantWithdrawalCashRespDTO;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.CashAdvanceEntity;
import com.cloudfun.campusshare.entity.MerchantAccountEntity;
import com.cloudfun.campusshare.entity.SubMerchantEntity;
import com.cloudfun.campusshare.entity.WithdrawApplicationEntity;
import com.cloudfun.campusshare.repo.CashAdvanceEntityRepo;
import com.cloudfun.campusshare.repo.WithdrawApplicationRepo;
import com.cloudfun.campusshare.service.*;
import com.cloudfun.campusshare.util.AmountUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * Created by CodeGenerator on 2020/08/14
 */
@Slf4j
@Service
public class WithdrawApplicationServiceImpl implements WithdrawApplicationService {

    @Autowired
    private WithdrawApplicationRepo withdrawApplicationRepo;

    @Autowired
    private KjtService kjtService;

    @Autowired
    private KjtSubMerchantService subMerchantService;

    @Autowired
    private MerchantAccountService merchantAccountService;

    @Autowired
    private WithdrawHisService withdrawHisService;

    @Override
    public void withdraw(WithdrawApplicationDTO applicationDTO) {
        List<WithdrawApplicationEntity> processingApplicationList = withdrawApplicationRepo.findByUserIdAndStatus(AuthenticationHolder.getUserId(), KjtAuditStatus.P);
        if (CollectionUtil.isNotEmpty(processingApplicationList)) {
            throw new BusinessException(Code.ERROR, "当前有正在处理的提现申请");
        }
        // 余额检查
        MerchantAccountEntity merchantAccountEntity = merchantAccountService.getEntityByUserId(AuthenticationHolder.getUserId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        Integer availableBalance = merchantAccountEntity.getAvailableBalance();
        if (StringUtils.isBlank(applicationDTO.getWithdrawalAmount())) {
            // 没传提现金额，则提取全部
            applicationDTO.setWithdrawalAmount(AmountUtil.amountRoundStr(merchantAccountEntity.getAvailableBalance(), 2));
        } else if (availableBalance < AmountUtil.strAmount2Int(applicationDTO.getWithdrawalAmount())) {
            // 否则判断金额和余额
            throw new BusinessException(Code.ERROR, "可用余额不足");
        }

        // 结算方式检查
        SubMerchantEntity subMerchantEntity = subMerchantService.getEntityByUserId(AuthenticationHolder.getUserId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        if (SettleType.MANUAL_WITHDRAWAL != subMerchantEntity.getSettleType()) {
            throw new BusinessException(Code.ERROR, "当前结算方式为委托体现，不能进行手动提现");
        }
        BankType companyOrPerson = subMerchantEntity.getCompanyOrPerson();
        KjtPayProductCode payProductCode = BankType.TO_B == companyOrPerson ? KjtPayProductCode.TO_B : KjtPayProductCode.TO_C;

        // 创建
        WithdrawApplicationEntity withdrawApplicationEntity = new WithdrawApplicationEntity();
        withdrawApplicationEntity.setSubMerchantId(subMerchantEntity.getId());
        withdrawApplicationEntity.setUserId(subMerchantEntity.getUserId());
        withdrawApplicationEntity.setPayProductCode(payProductCode);
        withdrawApplicationEntity.setWithdrawalAmount(AmountUtil.strAmount2Int(applicationDTO.getWithdrawalAmount()));
        withdrawApplicationEntity.setMemo(applicationDTO.getMemo());
        withdrawApplicationEntity.setStatus(KjtAuditStatus.P);
        withdrawApplicationRepo.save(withdrawApplicationEntity);
        KjtSubMerchantWithdrawalCashReqDTO reqDTO = this.buildWithdrawCashReqDTO(withdrawApplicationEntity);
        reqDTO.setIdentityId(subMerchantEntity.getIdentityId());
        // 发起请求
        KjtSubMerchantWithdrawalCashRespDTO withdrawalCashRespDTO = kjtService.subMerchantWithdrawalCash(reqDTO);
        this.handleWithdrawResp(withdrawalCashRespDTO);
    }

    @Override
    public void handleWithdrawResp(KjtSubMerchantWithdrawalCashRespDTO withdrawalCashRespDTO) {
        WithdrawApplicationEntity withdrawApplicationEntity = withdrawApplicationRepo.findById(withdrawalCashRespDTO.getOutTradeNo()).orElseThrow(() -> new BusinessException(Code.NODATA));
        withdrawApplicationEntity.setOutTradeNo(withdrawalCashRespDTO.getTradeNo());
        withdrawApplicationEntity.setStatus(withdrawalCashRespDTO.getStatus());
        withdrawApplicationEntity.setFailReason(withdrawalCashRespDTO.getFailReason());
        // 更新余额
        if (KjtAuditStatus.P == withdrawalCashRespDTO.getStatus()) {
            // 可用余额减
            merchantAccountService.updateAvailableBalance(withdrawApplicationEntity.getUserId(), -withdrawApplicationEntity.getWithdrawalAmount());
            // 冻结余额加
            merchantAccountService.updateFrozenBalance(withdrawApplicationEntity.getUserId(), withdrawApplicationEntity.getWithdrawalAmount());
        }
        withdrawApplicationRepo.save(withdrawApplicationEntity);
    }

    @Autowired
    private CashAdvanceEntityRepo cashAdvanceEntityRepo;

    @Override
    public boolean handleWithdrawNotify(KjtSubMerchantWithdrawalCashNotifyDTO notifyDTO) {
        WithdrawApplicationEntity withdrawApplicationEntity = withdrawApplicationRepo.findAllByOutTradeNo(notifyDTO.getOutTradeNo());
        CashAdvanceEntity byCashAdvanceNo = cashAdvanceEntityRepo.findByCashAdvanceNo(notifyDTO.getOutTradeNo());
        if (KjtAuditStatus.P == withdrawApplicationEntity.getStatus()) {
            KjtAuditStatus status = KjtWithdrawStatus.WITHDRAWAL_SUCCESS == notifyDTO.getWithdrawalStatus() ? KjtAuditStatus.S : KjtAuditStatus.F;
            withdrawApplicationEntity.setStatus(status);
            withdrawApplicationEntity.setOutTradeNo(notifyDTO.getInnerTradeNo());
            withdrawApplicationEntity.setWithdrawStatus(notifyDTO.getWithdrawalStatus());
            withdrawApplicationEntity.setFailReason(notifyDTO.getFailReason());
            withdrawApplicationEntity.setWithdrawTime(LocalDateTime.parse(notifyDTO.getGmtWithdrawal(), KjtSubMerchantWithdrawalCashNotifyDTO.GMT_WITHDRAWAL_FORMATTER));
            withdrawApplicationRepo.save(withdrawApplicationEntity);
            byCashAdvanceNo.setStatus(CashAdvanceStatus.SUCCESS);
        }else {
            byCashAdvanceNo.setStatus(CashAdvanceStatus.FAIL);
        }
        byCashAdvanceNo.setDescription(notifyDTO.getFailReason());
        cashAdvanceEntityRepo.save(byCashAdvanceNo);
        // 存储转账日志
        SubMerchantEntity subMerchantEntity = subMerchantService.getEntityById(withdrawApplicationEntity.getSubMerchantId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        WithdrawHisDTO withdrawHisDTO = new WithdrawHisDTO();
        withdrawHisDTO.setSubMerchantId(withdrawApplicationEntity.getSubMerchantId());
        withdrawHisDTO.setUserId(withdrawApplicationEntity.getUserId());
        withdrawHisDTO.setOutTradeNo(withdrawApplicationEntity.getOutTradeNo());
        withdrawHisDTO.setPayeeName(subMerchantEntity.getBankAccountName());
        withdrawHisDTO.setWithdrawalAmount(withdrawApplicationEntity.getWithdrawalAmount());
        withdrawHisDTO.setWithdrawStatus(withdrawApplicationEntity.getWithdrawStatus());
        withdrawHisDTO.setFailReason(withdrawApplicationEntity.getFailReason());
        withdrawApplicationEntity.setWithdrawTime(LocalDateTime.parse(notifyDTO.getGmtWithdrawal(), KjtSubMerchantWithdrawalCashNotifyDTO.GMT_WITHDRAWAL_FORMATTER));
        withdrawHisService.create(withdrawHisDTO);
//        // 更新余额
//        if (KjtWithdrawStatus.WITHDRAWAL_SUCCESS == notifyDTO.getWithdrawalStatus()) {
//            merchantAccountService.updateFrozenBalance(subMerchantEntity.getUserId(), -withdrawApplicationEntity.getWithdrawalAmount());
//        }
        return true;
    }

    /**
     * 构建快捷通子商户主动提现到卡请求DTO
     *
     * @param applicationEntity
     * @return
     */
    private KjtSubMerchantWithdrawalCashReqDTO buildWithdrawCashReqDTO(WithdrawApplicationEntity applicationEntity) {
        KjtSubMerchantWithdrawalCashReqDTO reqDTO = KjtSubMerchantWithdrawalCashReqDTO.builder()
                .outTradeNo(applicationEntity.getId())
                .partnerUserId(applicationEntity.getSubMerchantId())
                .bizProductCode("10210")
                .payProductCode(applicationEntity.getPayProductCode().getValue())
                .withdrawalAmount(AmountUtil.amountRoundStr(applicationEntity.getWithdrawalAmount(), 2))
                .memo(applicationEntity.getMemo())
                .build();
        return reqDTO;
    }

}